package test.patches;

import basemod.ReflectionHacks;
import com.evacipated.cardcrawl.modthespire.lib.*;
import com.evacipated.cardcrawl.modthespire.patcher.PatchingException;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.core.EnergyManager;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.potions.AbstractPotion;
import com.megacrit.cardcrawl.potions.BloodPotion;
import com.megacrit.cardcrawl.potions.EntropicBrew;
import com.megacrit.cardcrawl.potions.FruitJuice;
import com.megacrit.cardcrawl.relics.AbstractRelic;
import com.megacrit.cardcrawl.rooms.AbstractRoom;
import com.megacrit.cardcrawl.ui.panels.PotionPopUp;
import com.megacrit.cardcrawl.ui.panels.TopPanel;
import javassist.CannotCompileException;
import javassist.CtBehavior;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;
import mutsumimod.patches.CopyPatch;
import mutsumimod.patches.CopyWithTargetPatch;
import mutsumimod.relics.BaseRelic;
import test.relics.SoyoRelic;

import java.util.ArrayList;

public class SoyoRelicPatch {

    @SpirePatch(
            clz = AbstractPotion.class,
            method = SpirePatch.CLASS
    )
    public static class SoyoRelicFieldPatch {
        public static SpireField<Boolean> hasUsed = new SpireField<>(() -> false);
    }

    public static void destroyPotion(TopPanel topPanel,int slot) {
        if(AbstractDungeon.player.hasRelic(SoyoRelic.ID)&&AbstractDungeon.getCurrRoom().phase == AbstractRoom.RoomPhase.COMBAT) {
            return;
        }
        AbstractDungeon.topPanel.destroyPotion(slot);
    }

    @SpirePatch(
            clz = PotionPopUp.class,
            method = "updateInput"
    )
    public static class UpdateInputNotDestroyPatch {
        @SpireInstrumentPatch
        public static ExprEditor Instrument() {
            return new ExprEditor() {
                @Override
                public void edit(MethodCall m) throws CannotCompileException {
                    if (m.getClassName().equals(TopPanel.class.getName())
                            && m.getMethodName().equals("destroyPotion")&&m.getLineNumber()==288) {
                        m.replace("{ "
                                + SoyoRelicPatch.class.getName()
                                + ".destroyPotion($0,this.slot); }");
                    }
                }
            };
        }
    }

    @SpirePatch(
            clz = PotionPopUp.class,
            method = "updateTargetMode"
    )
    public static class UpdateTargetModeNotDestroyPatch {
        @SpireInstrumentPatch
        public static ExprEditor Instrument() {
            return new ExprEditor() {
                @Override
                public void edit(MethodCall m) throws CannotCompileException {
                    if (m.getClassName().equals(TopPanel.class.getName())
                            && m.getMethodName().equals("destroyPotion")) {
                        m.replace("{ "
                                + SoyoRelicPatch.class.getName()
                                + ".destroyPotion($0,this.slot); }");
                    }
                }
            };
        }
    }

    public static SpireReturn<Boolean> checkCanUse(AbstractPotion instance) {
        if (SoyoRelicFieldPatch.hasUsed.get(instance)) {
            return SpireReturn.Return(false);
        }
        return SpireReturn.Continue();
    }

    @SpirePatch(
            clz = AbstractPotion.class,
            method = "canUse"
    )
    public static class CanUsePatch {

        @SpirePrefixPatch
        public static SpireReturn<Boolean> prefix(AbstractPotion __instance) {
            return checkCanUse(__instance);
        }
    }

    @SpirePatch(
            clz = BloodPotion.class,
            method = "canUse"
    )
    public static class BloodPotionCanUsePatch {

        @SpirePrefixPatch
        public static SpireReturn<Boolean> prefix(AbstractPotion __instance) {
            return checkCanUse(__instance);
        }
    }

    @SpirePatch(
            clz = EntropicBrew.class,
            method = "canUse"
    )
    public static class EntropicBrewCanUsePatch {

        @SpirePrefixPatch
        public static SpireReturn<Boolean> prefix(AbstractPotion __instance) {
            return checkCanUse(__instance);
        }
    }

    @SpirePatch(
            clz = FruitJuice.class,
            method = "canUse"
    )
    public static class FruitJuiceCanUsePatch {

        @SpirePrefixPatch
        public static SpireReturn<Boolean> prefix(AbstractPotion __instance) {
            return checkCanUse(__instance);
        }
    }

    @SpirePatch(
            clz = PotionPopUp.class,
            method = "updateTargetMode"
    )
    public static class updateTargetModePatch {
        @SpireInsertPatch(
                locator = Locator.class
        )
        public static void insert(PotionPopUp __instance) {
            triggerBetterOnUsePotion(__instance);
        }
    }

    @SpirePatch(
            clz = PotionPopUp.class,
            method = "updateInput"
    )
    public static class updateInputPatch {
        @SpireInsertPatch(
                locator = Locator.class
        )
        public static void insert(PotionPopUp __instance) {
            triggerBetterOnUsePotion(__instance);
        }
    }

    public static void triggerBetterOnUsePotion(PotionPopUp __instance) {
        for(AbstractRelic r : AbstractDungeon.player.relics) {
            if(r instanceof BaseRelic) {
                AbstractPotion potion= ReflectionHacks.getPrivate(__instance,PotionPopUp.class, "potion");
                ((BaseRelic) r).betterOnUsePotion(potion);
            }
        }
    }

    private static class Locator extends SpireInsertLocator {
        public int[] Locate(CtBehavior ctMethodToPatch) throws CannotCompileException, PatchingException {
            Matcher finalMatcher = new Matcher.MethodCallMatcher(AbstractPotion.class, "use");

            int[] lines = LineFinder.findInOrder(ctMethodToPatch, new ArrayList<Matcher>(), finalMatcher);
            return new int[]{lines[0]+1};
        }
    }


}
